package vsvm.gui.controls;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

import vsvm.classifier.AbstractClassifier;
import vsvm.data.filter.AbstractFilter;
import vsvm.data.model.AbstractAttribute;
import vsvm.data.model.AbstractDataModel;
import vsvm.data.source.AbstractDataSource;
import vsvm.gui.Environment;
import vsvm.gui.IQuickInfoProvider;
import vsvm.gui.menus.ApplyFilterMenu;
import vsvm.gui.menus.AttributeMenu;
import vsvm.gui.menus.ClassifierMenu;
import vsvm.gui.menus.ClassifiersMenu;
import vsvm.gui.menus.DataModelMenu;
import vsvm.gui.menus.DataSourceMenu;
import vsvm.gui.menus.FilterMenu;
import vsvm.gui.menus.WorkspaceObjectMenu;
import vsvm.gui.objects.Workspace;

public class WorkspaceTree extends JTree {
	private static final long serialVersionUID = 100L;
	
	private class MouseHandler extends MouseAdapter {
		private WorkspaceTree tree;
		
		public MouseHandler(WorkspaceTree tree) {
			this.tree = tree;
		}

		@Override
		public void mousePressed(MouseEvent e) {
			if (e.isPopupTrigger() && tree.isEnabled()) {
				int selRow = getRowForLocation(e.getX(), e.getY());
				if (selRow<0) return;
				
		        TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());	
		        DefaultMutableTreeNode node = (DefaultMutableTreeNode)selPath.getLastPathComponent();
		        tree.setSelectionPath(selPath);
		        
		        tree.popupForNode(node, selPath, e.getX(), e.getY());
			}
		}	
		
		@Override
		public void mouseReleased(MouseEvent e) {
			if (e.isPopupTrigger() && tree.isEnabled()) {
				int selRow = getRowForLocation(e.getX(), e.getY());
				if (selRow<0) return;
				
		        TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());	
		        DefaultMutableTreeNode node = (DefaultMutableTreeNode)selPath.getLastPathComponent();
		        tree.setSelectionPath(selPath);
		        
		        tree.popupForNode(node, selPath, e.getX(), e.getY());
			}
		}
		
	}
	
	private DefaultMutableTreeNode dsNode;
    private DefaultMutableTreeNode dmNode;
    private DefaultMutableTreeNode fNode;
    private DefaultMutableTreeNode cNode;
    
    private Workspace workspace;
    private QuickInfoPanel qip = null;
	
	public WorkspaceTree(Workspace workspace, QuickInfoPanel qp) {
		this.qip = qp;
		this.setModel(getTreeModel(workspace));
		this.addMouseListener(new MouseHandler(this));
		this.addTreeSelectionListener(new TreeSelectionListener() {
				public void valueChanged(TreeSelectionEvent e) {
					Object obj = ((DefaultMutableTreeNode)e.getPath().getLastPathComponent()).getUserObject();
					if (obj instanceof IQuickInfoProvider) {
						if (qip != null)
							qip.setQuickInfo(((IQuickInfoProvider)obj).getQuickInfo());
					}
					else if (qip != null)
						qip.setQuickInfo("");
				}
			}
		);
		this.workspace = workspace;
	}
	
	public void popupForNode(DefaultMutableTreeNode node, TreePath selPath, int x, int y) {
		Object[] path = selPath.getPath();
		if (path.length < 2) return;
		
		DefaultMutableTreeNode cNode = (DefaultMutableTreeNode)path[1];
		
		if (cNode == dsNode) {
			if (node == dsNode) {
				JPopupMenu menu = DataSourceMenu.getPopup();
				menu.show(this, x, y);	
			} else {	// data source
				JPopupMenu menu = WorkspaceObjectMenu.getPopup(node.getUserObject());
				menu.show(this, x, y);				
			}
		} else if (cNode == dmNode) {
			if (node == dmNode) {
				JPopupMenu menu = DataModelMenu.getPopup();
				menu.show(this, x, y);	
			} else if (node.getUserObject() instanceof AbstractDataModel) {	// data model
				JPopupMenu menu = WorkspaceObjectMenu.getPopup(node.getUserObject());
				menu.show(this, x, y);				
			} else {	// attribute
				JPopupMenu menu = AttributeMenu.getPopup((AbstractAttribute)node.getUserObject());
				menu.show(this, x, y);
			}			
		} else if (cNode == fNode) {	// filter
			if (node == this.fNode) {
				JPopupMenu menu = FilterMenu.getPopup();
				menu.show(this, x, y);	
			} else {		// filter object
				JPopupMenu menu = ApplyFilterMenu.getPopup((AbstractFilter)node.getUserObject());
				menu.show(this, x, y);	
			}
			
		} else if (cNode == this.cNode) {
			if (node == this.cNode) {
				JPopupMenu menu = ClassifiersMenu.getPopup();
				menu.show(this, x, y);	
			} else {		// classifier object
				JPopupMenu menu = ClassifierMenu.getPopup((AbstractClassifier)node.getUserObject());
				menu.show(this, x, y);				
			}
		}
		
		
	}
	
	public DefaultTreeModel getTreeModel(Workspace ws) {
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("Workspace");
		
	    dsNode = new DefaultMutableTreeNode("Data sources");
	    dmNode = new DefaultMutableTreeNode("Data models");
	    fNode = new DefaultMutableTreeNode("Filters");
	    cNode = new DefaultMutableTreeNode("Classifiers");
	    
	    root.add(dsNode);
	    root.add(dmNode);
	    root.add(fNode);
	    root.add(cNode);
	    
	    if (ws != null) {
		    ArrayList<AbstractDataSource> ds = ws.getDataSources();
		    for (Iterator<AbstractDataSource> iter = ds.iterator(); iter.hasNext();) {
		    	AbstractDataSource d = iter.next();
		    	DefaultMutableTreeNode node = new DefaultMutableTreeNode(d.getName());
				node.setUserObject(d);
				dsNode.add(node);
		    }
		    
		    ArrayList<AbstractDataModel> dm = ws.getDataModels();
		    for (Iterator<AbstractDataModel> iter = dm.iterator(); iter.hasNext();) {
		    	AbstractDataModel d = iter.next();
		    	DefaultMutableTreeNode node = new DefaultMutableTreeNode(d.getName());
				node.setUserObject(d);
				
				for (int i = 0; i < d.getAttributeCount(); ++i) {
					DefaultMutableTreeNode n = new DefaultMutableTreeNode(d.getAttribute(i));
					node.add(n);					
				}
				
				dmNode.add(node);
		    }
			
		    ArrayList<AbstractFilter> fil = ws.getFilters();
		    for (Iterator<AbstractFilter> iter = fil.iterator(); iter.hasNext();) {
				AbstractFilter d = iter.next();
		    	DefaultMutableTreeNode node = new DefaultMutableTreeNode(d.getName());
				node.setUserObject(d);

				fNode.add(node);
		    }
			
		    ArrayList<AbstractClassifier> cls = ws.getClassifiers();
		    for (Iterator<AbstractClassifier> iter = cls.iterator(); iter.hasNext();) {
				AbstractClassifier d = iter.next();
		    	DefaultMutableTreeNode node = new DefaultMutableTreeNode(d.getName());
				node.setUserObject(d);
					
				cNode.add(node);
		    }
	    }
	    
	    return new DefaultTreeModel(root);
	}
	
	public void reload() {
		this.workspace = Environment.getEnvironment().getWorkspace();
		this.setModel(getTreeModel(workspace));
		this.setExpandsSelectedPaths(true);
	}
	
	
	public void colapse() {
		for (int i = 0; i < this.getRowCount(); ++i)
			this.collapseRow(i);
	}
	
	public void expand() {
		for (int i = 0; i < this.getRowCount(); ++i)
			this.expandRow(i);
	}
	
	public void colapse(int h) {
		this.expand();
		for (int i = 0; i < this.getRowCount(); ++i)
			if (this.getPathForRow(i).getPathCount() >= h) this.collapseRow(i);
	}
	
	public void expand(int h) {
		this.colapse();
		for (int i = 0; i < this.getRowCount(); ++i)
			if (this.getPathForRow(i).getPathCount() <= h) this.expandRow(i);
	}

	
	 public static void main(String[] args) {
		 JFrame frm = new JFrame();
		 WorkspaceTree wt = new WorkspaceTree(new Workspace(), null);
		 frm.add(wt);
		 frm.setVisible(true);
		 
     }
}
